﻿using _22_JWT封装.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace _22_JWT封装.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]

    public class jwt提前过期Controller : ControllerBase
    {
        // 解决思路：
        // 1、在数据库中用户表中增加个版本字段。
        // 2、生成jwt的时候把版本字段放进去
        // 3、访问验证的时候读取版本号和数据库里的用户表中版本号字段做对比，只要小于这个版本号的 jwt 都是人为过期的。不能访问接口 ,在filter中验证


        private readonly IOptionsSnapshot<JWTSettings> _jwtSettingOpt;
        private readonly UserManager<MyUser> _userManager;

        public jwt提前过期Controller(IOptionsSnapshot<JWTSettings> jwtSettingOpt,UserManager<MyUser> userManager)
        {
            this._jwtSettingOpt = jwtSettingOpt;
            this._userManager = userManager;
        }
        [HttpPost]
        [JWTNotCheckAttribute]
        public async Task<ActionResult<string>> Login(string userName, string passWord)
        {
            var user = await _userManager.FindByNameAsync(userName);
            if (user == null)
            {
                return BadRequest("用户名或者密码错误");
            }
            if (await _userManager.CheckPasswordAsync(user, passWord)) // 判断账号密码是否正确
            {
                // 重置登录次数
                await _userManager.ResetAccessFailedCountAsync(user).CheckAsync();
                user.JWTVersion++; //!!
                await _userManager.UpdateAsync(user); //!!

                List<Claim> claims = new List<Claim>();
                claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
                claims.Add(new Claim(ClaimTypes.Name, user.UserName));
                claims.Add(new Claim("JWTVersion", user.JWTVersion.ToString())); //!! 把版本号也放进令牌中
                var roles = await _userManager.GetRolesAsync(user); // 获取角色
                foreach (var role in roles)
                {
                    claims.Add(new Claim(ClaimTypes.Role, role));
                }
                string key = _jwtSettingOpt.Value.SetKey;
                DateTime expire = DateTime.Now.AddSeconds(_jwtSettingOpt.Value.ExpireSeconds);

                byte[] secBytes = Encoding.UTF8.GetBytes(key);
                var secKey = new SymmetricSecurityKey(secBytes);
                var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
                var tokenDescript = new JwtSecurityToken(claims: claims, expires: expire, signingCredentials: credentials);
                string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescript);
                return jwt;


            }
            else {
                await _userManager.AccessFailedAsync(user).CheckAsync();
                return BadRequest("用户名和密码错误");
            }

        }
        


        

        
    }
}
